home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 2 / ETO Development Tools 2.iso / Tools - Objects / MacApp / MacApp CD Release / MacApp 2.0.1 (Many Libraries) / Interfaces / CIncludes / UMemory.h < prev    next >
Encoding:
Text File  |  1990-10-25  |  20.8 KB  |  402 lines  |  [TEXT/MPS ]

  1. /*[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]*/
  2. /* UMemory.p */
  3. /* Copyright © 1985-1990 by Apple Computer, Inc.  All rights reserved. */
  4.  
  5. /*
  6.     This unit implements MacApp's memory management and segment management
  7.     schemes.
  8.  
  9.     The memory management scheme works by distinguishing between "permanent"
  10.     and "temporary" heap allocation requests.    Permanent requests are
  11.     typically used for data your application allocates:  objects and
  12.     handles.  Temporary requests are used for code segments and Toolbox
  13.     resources and data, such as WDEF's and CDEF's.
  14.  
  15.     Permanent memory objects are considered permanent because they
  16.     are not purged from memory until you explicitly dispose of or free them.
  17.     (Of course, the Macintosh Memory Manager will purge them if they're
  18.     marked purgeable.)    Permanent objects are allocated with NewPermHandle.
  19.     This prevents the MacApp GrowZone from purging temporary objects to
  20.     accommodate a permanent one.  In MacApp, all TObjects and its descendants
  21.     are considered permanent, and are allocated with NewPermHandle.
  22.  
  23.     Temporary memory objects are considered temporary because MacApp's
  24.     GrowZone procedure may purge them from memory to satisfy a memory
  25.     allocation request.  This is true regardless of whether the object is
  26.     marked non-purgeable, although the GrowZone procedure will not purge
  27.     locked objects (such as code segments in use).    Typically, temporary
  28.     objects are marked non-purgeable so that MacApp's GrowZone can control
  29.     when they are purged.
  30.  
  31.     MacApp reserves a specific amount of heap space for temporary objects,
  32.     the idea being that the space reserved is large enough to handle the
  33.     largest number of temporary objects (e.g. code and system resources)
  34.     needed at any given time.    If this amount is sufficiently large, your
  35.     program will never fail loading a segment or system resource.    This
  36.     amount is defined by the internal variable pSzCodeReserve.    You can
  37.     retrieve its value by calling GetReserveSize.    It is initially set by
  38.     the 'seg!' and 'mem!' resources, and can be changed at run-time by
  39.     calling SetReserveSize.  The procedure BuildCodeReserve reserves the
  40.     space by allocating the handle pCodeReserve and setting its size to
  41.     pSzCodeReserve - (the total size of all temporary objects in memory
  42.     [at that time]).
  43.  
  44.     When a temporary object is loaded into memory, the size of pCodeReserve
  45.     is adjusted accordingly. Permanent objects can be loaded into memory
  46.     only so long as there will still be at least pSzCodeReserve bytes
  47.     available for temporary objects.
  48.  
  49.     To identify which objects in the heap are temporary, MacApp maintains
  50.     four lists of handles.    The objects identified by these handles are
  51.     considered temporary and fall under the control of MacApp's GrowZone
  52.     procedure.    The lists are:
  53.  
  54.     gCodeSegs - A list of handles to all CODE resources in the application
  55.     and system resource forks.
  56.  
  57.     gSysMemList - A list handles to RAM-based system resources.
  58.     By default this list includes all PACK, LDEF, MDEF, CDEF and WDEF
  59.     resources in the system and application resource forks. You can add
  60.     other resources, such as fonts, by calling AddHandle.
  61.  
  62.     gApp1MemList, gApp2MemList - Lists of handles to application data or
  63.     resources.    MacApp initializes both lists to NIL.  The difference
  64.     between the two lists is that handles in gApp1MemList are purged
  65.     before those in gApp2MemList.  You may add your own handles to these
  66.     lists by allocating them with NewHandle and calling AddHandle for each
  67.     handle to be added to the list.
  68.  
  69.     The Macintosh Memory Manager calls MacApp's GrowZone procedure only when
  70.     all purgeable objects have been purged from the heap and there is still
  71.     insufficient space to satisfy a memory request.  The GrowZone will
  72.     look through the lists of temporary objects in memory, making one
  73.     purgeable so long as there is still at least pSzCodeReserve bytes
  74.     allocated to temporary memory (the total size of the temporary objects
  75.     in memory and the pCodeReserve handle).  The GrowZone procedure attempts
  76.     to never allow the size of the temporary objects and reserve to fall
  77.     below pSzCodeReserve, thereby guaranteeing that space is always avail-
  78.     able for code segments and system resources (provided pSzCodeReserve is
  79.     large enough to handle your application at its most memory intensive
  80.     state).
  81.  
  82.     The value of pSzCodeReserve is determined at startup-time by adding up
  83.     the size of all the segments named in the 'seg!' resources, and adding
  84.     the first value of each of the 'mem!' resources.  You can derive these
  85.     resources by observing your program and using the MacApp debugger to
  86.     help you determine when your application uses the largest amount of
  87.     code and system resources.    Typically, we've found that this happens
  88.     while printing on the LaserWriter, or during initialization or term-
  89.     ination.
  90.  
  91.     MacApp maintains another reserve, known as the low memory reserve.
  92.     This is a kind of emergency reserve--when all else fails we release
  93.     the pMemReserve handle.  Its size is initially determined by the second
  94.     number of each 'mem!' resource, and can be changed by calling
  95.     SetReserveSize.  You can retrieve its size by calling GetReserveSize.
  96.     Internally, the low-memory reserve is allocated with the pMemReserve
  97.     handle, and its size is stored in pSzMemReserve.
  98.  
  99.     The procedure InitUMemory is responsible for initially setting up the
  100.     temporary and low-memory reserves, setting up the GrowZone procedure,
  101.     initializing handle lists, and patching LoadSeg.  It signals failure
  102.     if the temporary reserve could not be allocated.
  103. */
  104.  
  105. #ifndef  __UMemory__
  106. #define __UMemory__  0
  107. #endif
  108. #if  ! __UMemory__
  109. #define __UMemory__  1
  110.  
  111.         /* • Auto-Include the requirements for this unit's interface. */
  112. #ifndef  __TYPES__
  113. #include "Types.h"
  114. #endif
  115. #ifndef  __MEMORY__
  116. #include "Memory.h"
  117. #endif
  118. #ifndef  __UPatch__
  119. #include "UPatch.h"
  120. #endif
  121.  
  122. const long kGZMaxAlloc           = 0x7FFFFFFF;
  123. const unsigned long kCode                = 'CODE';        /* Resource type for code */
  124.  
  125. typedef Handle AHandleList[5000];                             /* A list of handles */
  126. typedef AHandleList *HandleListPtr;                        /* Preferred */
  127. typedef HandleListPtr *HandleListHandle;                /* Preferred */
  128. typedef HandleListPtr PHandleList;                        /* Left in for compatibility (2.0) */
  129. typedef HandleListHandle HHandleList;                    /* Left in for compatibility (2.0) */
  130.  
  131. typedef Boolean ABoolList[5000];                              /* A list of BOOLEAN */
  132. typedef ABoolList *BoolListPtr;
  133. typedef BoolListPtr *BoolListHandle;
  134.  
  135. typedef long ALongList[5000];                                  /* A list of LONGINT */
  136. typedef ALongList *LongListPtr;
  137. typedef LongListPtr *LongListHandle;
  138.  
  139. extern pascal Size gMaxLockedRsrc;                        /* The maximum memory consumed by locked
  140.                                                          resources. See CheckRsrcUsage procedure. */
  141. #if  qDebug
  142. extern pascal Boolean gMemMgtBreak;                        /* if TRUE, break into debugger rather than
  143.                                                          just report memory mgt. information */
  144. extern pascal Boolean gRsrcReport;                        /* Report resource maximums to the debugger
  145.                                                          window. */
  146. extern pascal Boolean gSegReport;                        /* Report segment loadings to the debugger
  147.                                                          window. */
  148. #endif
  149. extern pascal HandleListHandle gSysMemList;                /* List of system handles used to compute
  150.                                                          current allocated temporary memory (all
  151.                                                          PACK, LDEF, MDEF, CDEF, WDEF resources).
  152.                                                          See ScanHandles procedure. */
  153. extern pascal HandleListHandle gApp1MemList,            /* an application defined memlist */
  154. gApp2MemList;                                            /* These start out NIL. You can create lists
  155.                                                          of handles and place then in either of
  156.                                                          these variables. (One list might be
  157.                                                          permanent handles in your application, and
  158.                                                          the other based on the current situation.)
  159.                                                          The values stored here should be a handle
  160.                                                          to a list of other handles. If you modify
  161.                                                          either of these lists, call CheckReserve.
  162.                                                          It calls BuildAllReserves to recompute the
  163.                                                          code and low space reserve. CheckReserve's
  164.                                                          result indicates whether the full code
  165.                                                          reserve is present. If not, then your
  166.                                                          program may crash because a segment (or
  167.                                                          defproc) can't be loaded. The handles in
  168.                                                          the lists should normally be resources
  169.                                                          that your application might require at any
  170.                                                          given time. All these handles will
  171.                                                          normally be marked non-purgeable. The
  172.                                                          GrowZone proc, however, can purge any of
  173.                                                          these handles that are not locked.*/
  174.  
  175. extern pascal short gCodeRefNum;                        /* Reference to where to find code segements
  176.                                                          */
  177.  
  178. extern pascal HandleListHandle gCodeSegs;                /* List of all code segments */
  179. extern pascal BoolListHandle gIsLoadedSeg;                /* Maintains a flag for each segment,
  180.  
  181.                                                          indicating whether the segment 
  182.    is loaded (in the
  183.                                                          segment loader sense).  Thereby optimizing
  184.                                                          UnloadAllSegments. */
  185. extern pascal BoolListHandle gIsResidentSeg;            /* Maintains a flag for each segment,
  186.  
  187.                                                          indicating whether the segment is resident
  188.                                                          and hence should not be unloaded (in the
  189.                                                          segment loader sense). */
  190.  
  191. extern pascal Boolean gUnloadAllSegs;                    /* UnloadAllSegments doesn't unload segments
  192.                                                         if this flag is false. */
  193.  
  194. extern pascal Ptr gGZPurgeNotify;                        /* If non-NIL, then this will be called
  195.                                                          before the Grow Zone proc purges a handle.
  196.                                                          The proc will be passed the actual handle.
  197.                                                          */
  198.             /* These are meant to be private but are in the interface just in case. */
  199. extern pascal LongListHandle pSegSize;                    /* Maintains size of each code resource. */
  200.  
  201. extern pascal Handle pCodeReserve;                        /* Allocates temporary (code) reserve. */
  202. extern pascal Handle pMemReserve;                        /* Allocates low memory reserve. */
  203. extern pascal Boolean pOKCodeReserve;                    /* if TRUE then we have an adequate code
  204.                                                          reserve; if FALSE then the application
  205.                                                          could crash if memory is tight */
  206. extern pascal Boolean pPermAllocation;
  207. extern pascal Boolean pReserveExists;                    /* TRUE if the code reserve is known to be
  208.                                                          fully allocated */
  209. #if  qDebug
  210. extern pascal long pReserveShortfall;                    /* amt. that we are lacking in the code
  211.                                                          reserve */
  212. #endif
  213. extern pascal Size pSzCodeReserve;                        /* Attempt to reserve this much memory for
  214.                                                          the temporary (code) reserve. */
  215. extern pascal Size pSzMemReserve;                        /* Attempt to reserve this much memory for
  216.                                                          the low-memory reserve. */
  217.  
  218. extern pascal TrapPatch pSegLoadPatch;                    /* patch for LoadSeg */
  219.  
  220. extern pascal short pOldResFile;                        /* The res file reference saved across
  221.                                                          segloads */
  222. extern pascal Boolean pLoadSegCalledFromOwnApp;
  223.    /* TRUE if calling LoadMacAppSeg from the app
  224.                                                          and not from a _DA_ in our own heap.
  225.                                                          (wheels within wheels for Pete's sake!) */
  226.  
  227. extern pascal short pMaxSegNum;                            /* The maximum segment number */
  228.  
  229.             /* I N I T I A L I Z A T I O N */
  230.  
  231. extern pascal void InitUMemory(void);
  232.         /* Initializes this unit. Must be called before using this unit. The caller must be in the
  233.         program's main segment. Sets up the gCodeSegs and gSysMemList handle lists, sets the grow
  234.         zone, calls MaxApplZone, sets gApp1MemList and gApp2MemList to NIL, patches LoadSeg and
  235.         allocates the temporary and low-memory reserves. Fails if unable to allocate the temporary
  236.         reserve. */
  237.  
  238.         /* S E G M E N T   L O A D I N G */
  239.  
  240.         /* DEBUGGING NOTE: You cannot set a MacApp breakpoint at any of these
  241.         routines, because they must not call anything (eg. %_BP) that may
  242.         require a segment load. */
  243.  
  244. extern pascal short GetSegNumber(Ptr aProc);
  245.         /* GetSegNumber returns the number of the segment in which aProc resides. */
  246.  
  247. extern pascal short GetSegFromPC(long ppc);
  248.         /* Given a pc pointer, return the segment number or 0 if not found.
  249.         Must be a loaded code segment. */
  250.  
  251. extern pascal Size GetSegSize(short segnum);
  252.         /* GetSegSize returns the size, in bytes, of the segment whose number is segnum. */
  253.  
  254. extern pascal long LoadMacAppSegment(short segnum);
  255.         /* This function patches LoadSeg. It is called from the assembly-language routine
  256.         AMacAppLoadSeg, which is the actual patch setup by PatchTrap. AMacAppLoadSeg saves
  257.         registers and sets up the stack by 1) allocating space for LoadMacAppSegment's result,
  258.  
  259.         and 2) pushing a copy of LoadSeg's parameter onto the stack for use by LoadMacAppSegment.
  260.         Signals failure if the segment could not be loaded. */
  261.  
  262. extern pascal void LoadResidentSegments(void);
  263.         /* Makes resident the segments whose names are included in any 'res!' resources. */
  264.  
  265. extern pascal Boolean PreloadSegment(short segnum);
  266.         /* PreloadSegment calls PreloadSegmentResource to load a segment in the resource manager
  267.         sense and then calls the segment loader to load it in the segment loader sense. */
  268.  
  269. extern pascal Boolean PreloadSegmentResource(short segnum);
  270.         /* PreloadSegment is available to programmers who want to lock a segment at the top of the
  271.         heap without having to call a dummy procedure in that segment. It is also useful for
  272.         determining whether a segment can in fact be loaded before you try to execute code in it.
  273.         PreloadSegment returns TRUE if the segment could be loaded, false otherwise. */
  274.  
  275. extern pascal void SetResidentSegment(short segnum, Boolean makeResident);
  276.         /* SetResidentSegment can be used to make a segment resident (or no longer resident); re
  277.            sident
  278.         segments will not be unloaded by UnloadAllSegments; if a segment is made resident, it is
  279.         also preloaded.MacApp® automatically marks its resident segment as resident (the one
  280.         containing the procedure CmdFromMenuItem); you probably should do UnloadAllSegments before
  281.         making a segment resident, to ensure that it is locked at the top of the heap. */
  282.  
  283. extern pascal void UnloadAllSegments(void);
  284.         /* UnloadAllSegments unloads all segments except the blank segment or the ones marked
  285.         resident. It is called at each iteration of the main event loop to compact memory, as well
  286.         as other places where compacting memory is needed or desirable. */
  287.  
  288.         /* H A N D L E L I S T   M A N A G E M E N T */
  289.  
  290. extern pascal void AddHandle(Handle h, HandleListHandle toList);
  291.         /* Adds a handle to the list of handles; does not check if the handle already exists in the
  292.         list. Simply calls Munger to add to the front of the list. */
  293.  
  294. extern pascal void AddAllRsrc(ResType rType, HandleListHandle toList);
  295.         /* Adds all the resources of type rType to the list. Filters out all ROM resources.Calls
  296.  
  297.         AddHandle. */
  298.  
  299. extern pascal void RemHandle(Handle h, HandleListHandle toList);
  300.         /* Removes the handle from list. */
  301.  
  302. extern pascal void ScanHandles(pascal void (*DoToHandle)(Handle h, void *DoToHandle_StaticLink), 
  303.    void *DoToHandle_StaticLink);
  304.         /* Calls DoToHandle for each handle in the lists gCodeSegs, gSysMemList, gApp1MemList and
  305.         gApp2MemList. This procedure assumes that DoToHandle does not compact memory. */
  306.  
  307.         /* M E M O R Y M A N A G E M E N T */
  308.  
  309. extern pascal void BuildAllReserves(void);
  310.         /* BuildAllReserves creates the code (temporary memory) and low space reserves. These ar
  311.            e kept
  312.         for use at a time when an out-of-memory condition has occurred to allow most such
  313.         occurrances to recover smoothly by deallocating the space. */
  314.  
  315. extern pascal Boolean CheckReserve(void);
  316.         /* Checks to see if the code reserve is OK. Calls BuildAllReserves and returns true if the
  317.         full code reserve is present. If this returns false your application may bomb because a
  318.         segment or system resource can't be loaded. */
  319.  
  320. #if  qDebug
  321.  
  322. extern pascal void CheckRsrcUsage(void);
  323.         /* Checks to see if the total size of the currently loaded resources exceeds the maximum
  324.         (gMaxLockedRsrc).If so, the new maximum is set.If gRsrcReport is true, then the new maximum
  325.         is reported in the debugger window.If gMemMgtBreak then program execution is stopped. */
  326. #endif
  327. #if  qDebug
  328.  
  329. extern pascal void DoChangeReserve(Boolean alter, Size *codeReserve, Size *codeShort, Size *
  330.    lowSpaceReserve, Boolean *gotCode, Boolean *gotLowSpace);
  331.         /* Called by the MacApp® debugger to change the reserve allocation. Not normally called 
  332.            by an
  333.         application. */
  334. #endif
  335.  
  336. extern pascal void FailNoReserve(void);
  337.         /* IF NOT CheckReserve THEN Failure(memFullErr, 0). */
  338.  
  339. extern pascal void FailSpaceIsLow(void);
  340.         /* IF MemSpaceIsLow THEN Failure(memFullErr, 0). */
  341.  
  342. extern pascal void GetReserveSize(Size *szCodeReserve, Size *szMemReserve);
  343.         /* Returns the amount of memory that is to be reserved for the code and memory reserve. This
  344.         is not a true indication of whether this amount of memory has in fact been reserved. Call
  345.         CheckReserve to find out if the code reserve could be allocated, and call MemSpaceIsLow to
  346.         find out if the low-memory reserve could be allocated. */
  347.  
  348. extern pascal Boolean MemSpaceIsLow(void);
  349.         /* Returns TRUE if the low space reserve is missing. */
  350.  
  351. extern pascal Ptr NewPermPtr(Size logicalSize);
  352.         /* Allocates a permanent Pointer; you should call this instead of NewPointer if allocating
  353.         some permanent memory. */
  354.  
  355. extern pascal Handle NewPermHandle(Size logicalSize);
  356.         /* Allocates a permanent handle; you should call this instead of NewHandle if allocating
  357.             some
  358.         permanent memory. */
  359.  
  360. extern pascal Boolean PermAllocation(Boolean permanent);
  361.         /* PermAllocation controls whether subsequent memory allocations are considered permanent or
  362.         temporary.Pass TRUE to setup things for a permanent allocation.Returns the previous state
  363.         of the permanent flag. */
  364.  
  365. extern pascal void SetPermHandleSize(Handle h, Size newSize);
  366.         /* Use this call to size permanent handles. It sets/resets the permanent flag correctly and
  367.         does a FailMemError. */
  368.  
  369. extern pascal void SetPermPtrSize(Ptr p, Size newSize);
  370.         /* Use this call to size permanent pointers. It sets/resets the permanent flag correctly and
  371.         does a FailMemError. */
  372.  
  373. extern pascal void SetReserveSize(Size forCode, Size forOther);
  374.         /* Call this to set the size of the memory reserved for code (temporary) and permanent (low
  375.         memory) requests. */
  376.  
  377. extern pascal Size TotalTempSize(Boolean justLocked, Handle *canPurge);
  378.         /* TotalTempSize returns the total number of bytes of the temporary handles currently in RAM
  379.         (or only locked/in use handles if justLocked is TRUE).  CanPurge is set to an unlocked
  380.         handle that can be purged if desired.  Uses ScanHandles. */
  381.  
  382. #if  qDebug
  383.  
  384. extern pascal void WriteReserves(void);
  385.         /* WRITELN's the temporary reserve and low-memory reserves in the debug window. */
  386. #endif
  387.  
  388.         /* U T I L I T I E S */
  389.  
  390. extern pascal Size AddSegSizes(Handle segRsrc);
  391.         /* Returns the total size of the code segments whose names are in the string list segRrs
  392.            c. */
  393.  
  394. extern pascal void SetStackSpace(Size numBytes);
  395.         /* Set the stack space to at least numBytes. */
  396. #endif
  397.  
  398. extern pascal void WithCodeResFileDo(pascal void (*DoWithResFile)(void *DoWithResFile_StaticLink), 
  399.    void *DoWithResFile_StaticLink);
  400.         /* Ensure that the resource call is done against gCodeRefNum */
  401.  
  402.